#!/usr/bin/ksh
#
# connections - print inbound TCP connections by process.
#               Written in DTrace (Solaris 10 3/05).
#
# This displays the PID and command name of the processes accepting 
# connections, along with the source IP address and destination port number.
#
# $Id: connections 3 2007-08-01 10:50:08Z brendan $
#
# USAGE:	connections [-htvZ]
#
#		-t		# print timestamps, us
#		-v		# print timestamps, string
#		-Z		# print zonename
#	eg,
#		connections -v	# snoop connections with times
#
# FIELDS:
#		UID		user ID of the server
#		PID		process ID for the server
#		CMD		server command name
#		TIME		timestamp, us
#		TIMESTR		timestamp, string
#		PORT		server port
#		IP_SOURCE	source IP of the client, written in IPv4 style
#		ZONE		zonename
#
# SEE ALSO:	snoop 'tcp[13:1] = 0x02'	# snoop new connections
#
# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
#
# CDDL HEADER START
#
#  The contents of this file are subject to the terms of the
#  Common Development and Distribution License, Version 1.0 only
#  (the "License").  You may not use this file except in compliance
#  with the License.
#
#  You can obtain a copy of the license at Docs/cddl1.txt
#  or http://www.opensolaris.org/os/licensing.
#  See the License for the specific language governing permissions
#  and limitations under the License.
#
# CDDL HEADER END
#
# TODO: IPv6
#
# 10-Apr-2004	Brendan Gregg	Created this.
# 23-May-2004	   "      "  	Fixed issues on SPARC.
# 08-May-2005	   "      "  	Updated for newer Solaris 10.
# 17-Jun-2005	   "      "	Rewrote, changed probes, wrapped in sh.
# 04-Dec-2005	   "	  "	Changed tcp_accept_finish -> sotpi_accept
# 20-Apr-2006	   "	  "	Fixed SS_TCP_FAST_ACCEPT bug in build 31+.
# 20-Apr-2006	   "	  "	Last update.
#


##############################
# --- Process Arguments ---
#

### Default variables
opt_time=0; opt_timestr=0; opt_zone=0

### Process options
while getopts htvZ name
do
	case $name in
	t)      opt_time=1 ;;
	v)      opt_timestr=1 ;;
	Z)      opt_zone=1 ;;
	h|?)    cat <<-END >&2
		USAGE: connections [-htvZ]
			   -t              # print timestamps, us
			   -v              # print timestamps, string
			   -Z              # print zonename
		  eg,
		       connections -v      # snoop connections with times
		END
		exit 1
	esac
done


#################################
# --- Main Program, DTrace ---
#
/usr/sbin/dtrace -C -s <( print -r '
#include <sys/file.h>
#include <sys/types.h>
#include <sys/byteorder.h>
#include <sys/socket.h>
#include <sys/socketvar.h>

 #pragma D option quiet
 #pragma D option switchrate=10hz

 inline int OPT_time    = '$opt_time';
 inline int OPT_timestr = '$opt_timestr';
 inline int OPT_zone    = '$opt_zone';

 /*
  * Print header
  */
 dtrace:::BEGIN 
 {
        /* print optional headers */
        OPT_time    ? printf("%-14s ", "TIME") : 1;
        OPT_timestr ? printf("%-20s ", "TIMESTR") : 1;
	OPT_zone    ? printf("%-10s ", "ZONE") : 1;

	/* print header */
	printf("%5s %5s %-12s %4s %5s %s\n",
	    "UID", "PID", "CMD", "TYPE", "PORT", "IP_SOURCE");
 }

 /*
  * TCP Process inbound connections
  *
  * 0x00200000 has been hardcoded. It was SS_TCP_FAST_ACCEPT, but was
  * renamed to SS_DIRECT around build 31.
  */
 fbt:sockfs:sotpi_accept:entry
 /(arg1 & FREAD) && (arg1 & FWRITE) && (args[0]->so_state & 0x00200000)/
 {
	self->sop = args[0];
 }

 fbt:sockfs:sotpi_create:return
 /self->sop/
 {
	self->nsop = (struct sonode *)arg1;
 }


 /*
  * Probe TCP connections
  */
 fbt:sockfs:sotpi_accept:return
 /self->nsop/
 {
	/* fetch connection details */
	this->tcpp = (tcp_t *)self->nsop->so_priv;
	this->connp = (conn_t *)this->tcpp->tcp_connp;

#if defined(_BIG_ENDIAN)
	this->port0 = this->connp->u_port.tcpu_ports.tcpu_lport;
#else
	this->port0 = BSWAP_16(this->connp->u_port.tcpu_ports.tcpu_lport);
#endif
	this->rem12 = 
	    (uint8_t)this->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[12];
	this->rem13 =
	    (uint8_t)this->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[13];
	this->rem14 =
	    (uint8_t)this->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[14];
	this->rem15 =
	    (uint8_t)this->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[15];

        /* print optional fields */
        OPT_time    ? printf("%-14d ", timestamp/1000) : 1;
        OPT_timestr ? printf("%-20Y ", walltimestamp) : 1;
	OPT_zone    ? printf("%-10s ", zonename) : 1;

	/* print output line */
	printf("%5d %5d %-12s %4s %5d %d.%d.%d.%d\n",
	    uid, pid, execname, "tcp", this->port0, 
	    this->rem12, this->rem13, this->rem14, this->rem15);
 }

 fbt:sockfs:sotpi_accept:return
 {
	self->nsop = 0;
	self->sop = 0;
 }
')

